//
// Created by fuweicong on 2023/4/21.
//

#include <event2/buffer.h>
#include "peer_connect_client.h"



void read_cb(struct bufferevent *bev, void *ctx)
{
    fm::PeerConnectClient* peerConnectClient = static_cast<fm::PeerConnectClient*>(static_cast<fm::PeerConnectClient *>(ctx));
    peerConnectClient->onRead(bev);
}

void read_message_cb(struct bufferevent* bev, void *ctx){
    LOGE("新数据进来");
    fm::PeerConnectClient* peerConnectClient = static_cast<fm::PeerConnectClient*>(static_cast<fm::PeerConnectClient *>(ctx));
    peerConnectClient->onMessageRead(bev);
}

void write_cb(struct bufferevent *bev, void *ctx)
{
    // 数据写入完成的回调
    LOGE("发送完数据");
    fm::PeerConnectClient* peerConnectClient = static_cast<fm::PeerConnectClient*>(static_cast<fm::PeerConnectClient *>(ctx));

}

void event_cb(struct bufferevent *bev, short events, void *ctx)
{
    if (events & BEV_EVENT_CONNECTED) {
        LOGE("Connected to server.\n");
    } else if (events & BEV_EVENT_ERROR) {
        LOGE("Error in connection.\n");
    } else {
        LOGE("event");
    }
}


bool fm::PeerConnectClient::ReadIntoBuffer(struct bufferevent *bev, std::string &data) {
    char buffer[1024+1];
    int n;
    bool ret = false;
    evutil_socket_t fd = bufferevent_getfd(bev);
    do{
        n = bufferevent_read(bev, buffer, sizeof(buffer)-1);
        buffer[n] = '\0';
        LOGE("ndata %d ", n);
        data.append(buffer);
    } while (n > 0) ;

       // memset(line, 0, sizeof(line));  // 清空缓冲

    size_t i = data.find("\r\n\r\n");
    if (i != -1) {
        if (GetHeaderValue(data, i, "\r\nContent-Length: ", &content_length)) {

            size_t total_response_size = (i + 4) + content_length;
            LOGE("content length %d data length %d total_response_size length %d", content_length, data.length(), total_response_size);
            if (data.length() >= total_response_size) {
                ret = true;
                std::string should_close;
                const char kConnection[] = "\r\nConnection: ";
                if (GetHeaderValue(data, i, kConnection, &should_close)){
                    LOGE("返回了啥");
                    evutil_socket_t fd = bufferevent_getfd(bev);
                    // evutil_closesocket(fd);
                }
            } else {
                LOGE("数据长度不够");
            }
        }
    } else {
        LOGE("sdp 消息错误");
    }
    return ret;

}

/**
 * 获取 返回状态码
 * @param response
 * @return
 */
int fm::PeerConnectClient::GetResponseStatus(const std::string &response) {
    int status = -1;
    size_t pos = response.find(' ');
    if (pos != std::string::npos)
        status = atoi(&response[pos + 1]);
    return status;
}

void fm::PeerConnectClient::parse_peer_message(int peer_id, std::string message) {
    Json::CharReaderBuilder factory;
    callbackMessage->message(peer_id, message.data());
}

bool fm::PeerConnectClient::ParseServerResponse(const std::string &response, size_t content_length,
                                                size_t *peer_id, size_t *eoh) {

    int status = GetResponseStatus(response.c_str());
    if (status != 200) {
        LOGE("Received error from server");

        return false;
    }

    *eoh = response.find("\r\n\r\n");
    if (*eoh == std::string::npos)
        return false;

    *peer_id = -1;

    // See comment in peer_channel.cc for why we use the Pragma header.
    GetHeaderValue(response, *eoh, "\r\nPragma: ", peer_id);
    return true;

}

void fm::PeerConnectClient::onMessageRead(struct bufferevent *bev) {
    // 处理从服务器接收到的数据
    LOGE("onMessageRead 收到数据");

    if (ReadIntoBuffer(bev, data)) {
        LOGE("onRead content length %d", content_length);
        size_t peer_id = 0, eoh = 0;
        bool ok = ParseServerResponse(data, content_length, &peer_id, &eoh);
        if (ok) {
            size_t pos = eoh + 4;
            if (peer_id == this->client_id) {
                while (pos < data.size()) {
                    size_t eol = data.find('\n', pos);
                    if (eol == std::string::npos)
                        break;
                    int id = 0;
                    std::string name;
                    bool connected;
                    if (ParseEntry(data.substr(pos, eol - pos), &name, &id,
                                   &connected) &&
                        id != this->client_id) {
                        LOGE("id :%d ,name : %s", id, name.c_str());
                    }
                    pos = eol + 1;
                }
            } else {
                //parse_peer_message(peer_id, )
                LOGE("其他消息 peer_id %d", peer_id);
                parse_peer_message(peer_id, data.substr(pos));

            }

        }

        bufferevent_free(bev);
      //  LOGE("onMessageRead %s", data.c_str());
        this->read_message();
        this->data.clear();
    }

//    evutil_socket_t fd = bufferevent_getfd(bev);
//    evutil_closesocket(fd);



}

bool fm::PeerConnectClient::ParseEntry(const std::string& entry,
                                       std::string* name,
                                       int* id,
                                       bool* connected) {


    *connected = false;
    size_t separator = entry.find(',');
    if (separator != std::string::npos) {
        *id = atoi(&entry[separator + 1]);
        name->assign(entry.substr(0, separator));
        separator = entry.find(',', separator + 1);
        if (separator != std::string::npos) {
            *connected = atoi(&entry[separator + 1]) ? true : false;
        }
    }
    return !name->empty();
}


void fm::PeerConnectClient::onRead(struct bufferevent *bev) {

    // 处理从服务器接收到的数据
    LOGE("onRead 收到数据");
    std::string data;
    if (ReadIntoBuffer(bev, data)) {
        LOGE("onRead content length %d", content_length);
        size_t peer_id = 0, eoh = 0;
        bool ok = ParseServerResponse(data, content_length, &peer_id, &eoh);
        if (ok) {
            if (this->client_id == -1) {
                this->client_id = peer_id;
                //  wait(message_bev, peer_id);
                LOGE("onRead client id %d", this->client_id);
            }
            if (content_length) {
                size_t pos = eoh + 4;
                while (pos < data.size()) {
                    size_t eol = data.find('\n', pos);
                    if (eol == std::string::npos)
                        break;
                    int id = 0;
                    std::string name;
                    bool connected;
                    if (ParseEntry(data.substr(pos, eol - pos), &name, &id,
                                   &connected) &&
                        id != this->client_id) {
                        LOGE("id :%d ,name : %s", id, name.c_str());
                    }
                    pos = eol + 1;
                }
            }
        }

    }
    LOGE("onRead %s", data.c_str());
    bufferevent_free(bev);
    if (this->client_id != -1) {
        read_message();
    }
    send_message();

}





void fm::PeerConnectClient::start() {
    LOGE("start");

    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(port); // 服务器端口号
    inet_pton(AF_INET, ip, &serv_addr.sin_addr); // 服务器 IP 地址

    base = event_base_new();
    send_message();
    sign(bev);
    event_base_dispatch(base); // 进入事件循环
    // 清理资源
    bufferevent_free(bev);
    event_base_free(base);
    LOGE("END");
}

/**
 * 获取协议头信息
 * @param data
 * @param eoh
 * @param header_pattern
 * @param value
 * @return
 */
bool fm::PeerConnectClient::GetHeaderValue(const std::string& data,
                                           size_t eoh,
                                           const char* header_pattern,
                                           size_t* value) {
    size_t found = data.find(header_pattern);
    if (found != std::string::npos && found < eoh) {
        *value = atoi(&data[found + strlen(header_pattern)]);
        return true;
    }
    return false;
}

bool fm::PeerConnectClient::GetHeaderValue(const std::string& data,
                                           size_t eoh,
                                           const char* header_pattern,
                                           std::string* value) {
    size_t found = data.find(header_pattern);
    if (found != std::string::npos && found < eoh) {
        size_t begin = found + strlen(header_pattern);
        size_t end = data.find("\r\n", begin);
        if (end == std::string::npos)
            end = eoh;
        value->assign(data.substr(begin, end - begin));
        return true;
    }
    return false;
}


/**
 * 统一写出数据
 * @param bev
 * @param buffer
 * @param size
 */
void fm::PeerConnectClient::writeData(struct bufferevent *bev, char *buffer, int size) {
    //发送数据
    bufferevent_write(bev, buffer, size);
}

/**
 * 等待
 * @param bev
 */
void fm::PeerConnectClient::wait(struct bufferevent *bev, size_t id) {
    char buffer[1024];
    LOGE("wait %d", id);
    snprintf(buffer, sizeof(buffer), "GET /wait?peer_id=%i HTTP/1.0\r\n\r\n",
             id);
    writeData(bev, buffer, strlen(buffer));
}

/**
 * 统一建立连接
 * @param bev
 */
void fm::PeerConnectClient::sign(struct bufferevent *bev){
    //读数据
    char buf[1024];
    snprintf(buf, sizeof(buf), "GET /sign_in?%s HTTP/1.0\r\n\r\n",
             "fuweicong");
    writeData(bev, buf, sizeof(buf));
}


void fm::PeerConnectClient::read_message() {
    message_bev = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE);
    bufferevent_setcb(message_bev, read_message_cb, write_cb, event_cb, this);
    bufferevent_enable(message_bev, EV_READ | EV_WRITE);
    bufferevent_socket_connect(message_bev, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
    wait(message_bev, this->client_id);
}

void fm::PeerConnectClient::send_message() {
    bev = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE);
    // 设置事件回调函数
    bufferevent_setcb(bev,read_cb, write_cb, event_cb, this);
    bufferevent_enable(bev, EV_READ | EV_WRITE);
    bufferevent_socket_connect(bev, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
}



fm::PeerConnectClient::PeerConnectClient(CallbackMessage *callbackMessage):callbackMessage(callbackMessage) {

}


void fm::PeerConnectClient::sendMessage(int peer_id, const char *data) {
  //  struct bufferevent *bev = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE);
    std::string content;
    content.append(data);
    std::string body;
    char headers[1024];
    snprintf(headers, sizeof(headers),
             "POST /message?peer_id=%i&to=%i HTTP/1.0\r\n"
             "Content-Length: %zu\r\n"
             "Content-Type: text/plain\r\n"
             "\r\n",
             client_id, peer_id, content.length());
    LOGE("peer_id = %d , to = %d", client_id, peer_id);
    LOGE("data %s", data);
    body.append(headers);
    body.append(data);
    LOGE("data %s", body.data());
    writeData(bev, const_cast<char *>(body.c_str()), body.length());
}